package com.lcc.lynx.common.utils;

import com.lcc.lynx.common.exception.ParamsException;
import com.lcc.lynx.jdbc.util.JDBCReflectUtil;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 参数校验
 *
 * @author lcc
 */
public class CheckUtil {

    public interface RegionArr {
        String[] YN = new String[]{"0", "1"};
    }

    /**
     * @param params 需要校验的对象
     */
    public static CheckUtil of(Object params) {
        return of(params, "参数对象");
    }

    public static CheckUtil of(Object params, String name) {
        if (params == null) {
            throw new ParamsException(name + "不能为null");
        }
        return new CheckUtil(params);
    }

    public static  <R> CheckUtil ofList(List<R> items, String fieldKey, String fieldLabel, BiConsumer<CheckUtil, R> fun){
        CheckUtil self = new CheckUtil();
        return self.checkList(items, fieldKey, fieldLabel, fun);
    }

    private CheckUtil() {

    }

    CheckUtil(Object params) {
        this.params = params;
    }

    Object params;
    Object item; // 循环时的对象
    String dtlName; // 明细名称
    int index; // 循环时的下标
    /**
     * 错误信息列表
     */
    List<String> list = new ArrayList<>();

    public String getErrorMsg() {
        if (CollectionUtils.isEmpty(list)) return null;
        return String.join("; ", list);
    }

    public void throwException() {
        if (!list.isEmpty()) {
            throw new ParamsException(getErrorMsg());
        }
    }

    /**
     * 校验参数
     *
     * @param sf         get方法的lambda 表达式
     * @param fieldLabel 字段描述
     * @param minLen     最小长度
     * @param maxLen     最大长度
     * @param regEx      正则表达式
     * @param regionArr  可选范围
     */

    public final CheckUtil checkAll(SSupplier<?> sf, String fieldKey, String fieldLabel, int minLen, int maxLen,
                                    String regEx, String[] regionArr, String errMsg) {
        if(fieldKey == null){
            fieldKey = getFieldName(LambdaUtils.resolve(sf));
        }
        Object val0 = sf.get();
        if (val0 instanceof Collection<?> v && v.isEmpty()) {
            val0 = null;
        }
        String val = val0 == null ? null : val0.toString();
        return checkAll(val, fieldKey, fieldLabel, minLen, maxLen, regEx, regionArr, errMsg);
    }

    public final CheckUtil checkAll(String val, String fieldKey, String fieldLabel, int minLen, int maxLen,
                                    String regEx, String[] regionArr, String errMsg) {
        String dtlStr = getDtlStr();
        if (minLen > 0 && null == val) {
            list.add(dtlStr + fieldLabel + "(" + fieldKey + ")不能为null");
        } else if (minLen > 0 && val.trim().isEmpty()) {
            list.add(dtlStr + fieldLabel + "(" + fieldKey + ")不能为空");
        }
        if (null != val && !val.isEmpty()) {
            if (maxLen > 0 && val.length() > maxLen) {
                list.add(dtlStr + fieldLabel + "(" + fieldKey + ")值为" + val + "，要求长度不能大于" + maxLen);
            }
            if (minLen > 1 && val.length() < minLen) {
                list.add(dtlStr + fieldLabel + "(" + fieldKey + ")值为" + val + "，要求长度不能小于" + minLen);
            }
            if (null != regionArr && !contains(regionArr, val)) {
                if (errMsg != null && !errMsg.isEmpty()) {
                    list.add(errMsg);
                } else {
                    list.add(dtlStr + fieldLabel + "(" + fieldKey + ")值为" + val + "，不在允许的值范围" + Arrays.toString(regionArr));
                }
            }
            if (null != regEx && !regEx.isEmpty()) {
                Pattern pattern = Pattern.compile(regEx);
                // Pattern pat = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE); // 忽略大小写的写法
                Matcher matcher = pattern.matcher(val);
                // 字符串是否与正则表达式相匹配
                if (!matcher.matches()) {
                    list.add(Objects.requireNonNullElseGet(errMsg, () -> dtlStr + fieldLabel + "(" + fieldKey + ")值为" + val + "，不合法！正则要求：" + regEx));
                }
            }
        }
        return this;
    }

    private boolean contains(String[] regionArr, String val) {
        for (String str : regionArr) {
            if (str.equals(val)) {
                return true;
            }
        }
        return false;
    }

    public final CheckUtil check(SSupplier<?> sf) {

        return checkAll(sf, null, JDBCReflectUtil.getFieldLabel(sf, params), 1, -1, null, null, null);
    }

    public final CheckUtil check(SSupplier<?> sf, String fieldLabel) {
        return checkAll(sf, null, fieldLabel, 1, -1, null, null, null);
    }

    public final CheckUtil check(SSupplier<?> sf, String fieldKey, String fieldLabel) {
        return checkAll(sf, fieldKey, fieldLabel, 1, -1, null, null, null);
    }

    public final CheckUtil check(SSupplier<?> sf, String fieldLabel, int minLen, int maxLen) {
        return checkAll(sf, null, fieldLabel, minLen, maxLen, null, null, null);
    }

    /**
     * 不为空 正则校验
     */
    public final CheckUtil checkRegEx1(SSupplier<?> sf, String fieldLabel, String regEx, String errMsg) {
        return checkAll(sf, null, fieldLabel, 1, -1, regEx, null, errMsg);
    }

    /**
     * 可为空 正则校验
     */
    public final CheckUtil checkRegEx0(SSupplier<?> sf, String fieldLabel, String regEx, String errMsg) {
        return checkAll(sf, null, fieldLabel, 0, -1, regEx, null, errMsg);
    }

    public final CheckUtil checkArr1(SSupplier<?> sf, String fieldLabel, String[] regionArr, String errMsg) {
        return checkAll(sf, null, fieldLabel, 1, -1, null, regionArr, errMsg);
    }

    public final CheckUtil checkArr0(SSupplier<?> sf, String fieldLabel, String[] regionArr, String errMsg) {
        return checkAll(sf, null, fieldLabel, 0, -1, null, regionArr, errMsg);
    }

    /**
     * 根据条件添加msg到错误信息列表
     *
     * @param b   表达式
     * @param msg b为真时添加msg到list
     */
    public final CheckUtil check(boolean b, String msg) {
        if (b) list.add(getDtlStr() + msg);
        return this;
    }

    /**
     * 添加msg到错误信息列表
     *
     * @param msg 添加msg到list
     */
    public final CheckUtil addMsg(String msg) {
        list.add(msg);
        return this;
    }

    public CheckUtil addMsgIf(boolean b, String msg) {
        if (b) list.add(msg);
        return this;
    }

    /**
     * 获取错误信息列表
     *
     * @author lcc
     * @date 2024/8/13 15:06
     */
    public List<String> get() {
        return list;
    }

    /**
     * @param sf 列表get方法
     * @param fieldLabel 列表字段名
     * @param fun        明细处理函数，第一个参数为校验对象本身self，第二个参数为当前校验的item
     * @author lcc
     * @date 2024/8/13 15:08
     */
    public <R> CheckUtil checkList(SSupplier<List<R>> sf, String fieldLabel, BiConsumer<CheckUtil, R> fun) {
        String fieldKey = getFieldName(LambdaUtils.resolve(sf));
        List<R> val0 = sf.get();
        if (val0 == null) {
            list.add(fieldLabel + "列表(" + fieldKey + ")不能null");
            return this;
        }
        return checkList(val0, fieldKey, fieldLabel, fun);
    }

    public <R> CheckUtil checkList(List<R> items, String fieldKey, String fieldLabel, BiConsumer<CheckUtil, R> fun) {
        if (CollectionUtils.isEmpty(items)) {
            list.add(fieldLabel + "列表(" + fieldKey + ")不能为空");
        } else if (fun != null) {
            this.dtlName = fieldLabel;
            Object temp = this.params;
            for (int i = 0; i < items.size(); i++) {
                this.item = items.get(i);
                this.params = this.item;
                this.index = i;
                fun.accept(this, items.get(i));
                if (i == items.size() - 1) {
                    this.item = null;
                }
            }
            this.params = temp;
            this.dtlName = null;
        }
        return this;
    }

    public CheckUtil checkArray(SSupplier<?> sf, String fieldLabel) {
        String fieldKey = getFieldName(LambdaUtils.resolve(sf));
        Object val0 = sf.get();
        if (val0 == null) {
            list.add(fieldLabel + "数组(" + fieldKey + ")不能null");
        } else if (val0.getClass().isArray()) {
            if (Array.getLength(val0) == 0) {
                list.add(fieldLabel + "数组(" + fieldKey + ")不能为空");
            }
        } else {
            throw new ParamsException("字段(" + fieldKey + ")不是数组类型");
        }
        return this;
    }


    private String getFieldName(String fieldKey){
        return ReflectUtil.getJsonPropertyName(params.getClass(), fieldKey);
    }

    private String getDtlStr() {
        String dtlStr = "";
        if (this.item != null) {
            if (dtlName != null) {
                dtlStr += dtlName + "的";
            }
            dtlStr += "第" + (this.index + 1) + "条明细的";
        }
        return dtlStr;
    }

}
